Skip to content

fix: Pass request type to SelectiveDecimalColumnReader#17463

Open
beliefer wants to merge 6 commits into
facebookincubator:mainfrom
beliefer:17462
Open

fix: Pass request type to SelectiveDecimalColumnReader#17463
beliefer wants to merge 6 commits into
facebookincubator:mainfrom
beliefer:17462

Conversation

@beliefer
Copy link
Copy Markdown
Contributor

@beliefer beliefer commented May 8, 2026

Summary: when the leaf node (Scan operator) in one child of the Join operator is rolled back to Vanilla Spark, while the leaf node (Scan operator) in the other child still uses NativeScan, and the join key used by Join contains the decimal type, Spark ORC reader will prioritize using the decimal type in the table schema (e.g. DECIMAL (20,0)) over the decimal type in the ORC file (e.g. DECIMAL (38,18)) but Native ORC reader only using the decimal type in the ORC file, which ultimately leads to incorrect matching of the join key, resulting in the output of 0 rows after join.

Root cause:
Hive ORC fixed the DECIMAL (38,18) in footer, and the true scale of each row is written in the SECONDRY stream. The original ORC reader used footer's
The use of scale instead of the scale of the meta store (table schema) results in inconsistency between the output of NativeScan and Vanilla Spark.

Fixes: #17462

This PR proposes to pass the request type into SelectiveColumnReader.

This PR could help to fix apache/gluten#11980

@netlify
Copy link
Copy Markdown

netlify Bot commented May 8, 2026

Deploy Preview for meta-velox ready!

Name Link
🔨 Latest commit f906067
🔍 Latest deploy log https://app.netlify.com/projects/meta-velox/deploys/6a06c9cfc3f0c10008a57cff
😎 Deploy Preview https://deploy-preview-17463--meta-velox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 8, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Build Impact Analysis

Selective Build Targets (building these covers all 247 affected)

cmake --build _build/release --target aggregate_companion_functions_test physical_size_aggregator_test presto_sql_test spark_aggregation_fuzzer_test spark_expression_fuzzer_test velox_abfs_test velox_aggregates_GeometryAggregateTest velox_aggregates_reduce_agg_bm velox_aggregates_simple_aggregates_bm velox_aggregates_string_keys_bm velox_aggregates_test_group0 velox_aggregates_test_group1 velox_aggregates_test_group2 velox_aggregates_test_group3 velox_aggregates_test_group4 velox_aggregation_fuzzer_test velox_aggregation_runner_test velox_benchmark_array_writer_no_nulls velox_benchmark_array_writer_with_nulls velox_benchmark_map_writer_no_nulls velox_benchmark_map_writer_with_nulls velox_benchmark_nested_array_writer_no_nulls velox_benchmark_nested_array_writer_with_nulls velox_cache_fuzzer velox_common_test velox_core_test velox_driver_test velox_duckdb_conversion_test velox_dwio_cache_test velox_dwio_dwrf_buffered_output_stream_test velox_dwio_dwrf_byte_rle_encoder_test velox_dwio_dwrf_byte_rle_test velox_dwio_dwrf_checksum_test velox_dwio_dwrf_column_reader_test velox_dwio_dwrf_column_statistics_test velox_dwio_dwrf_compression_test velox_dwio_dwrf_config_test velox_dwio_dwrf_data_buffer_holder_test velox_dwio_dwrf_decompression_test velox_dwio_dwrf_decryption_test velox_dwio_dwrf_dictionary_encoder_test velox_dwio_dwrf_dictionary_encoding_utils_test velox_dwio_dwrf_encoding_selector_test velox_dwio_dwrf_encryption_test velox_dwio_dwrf_flush_policy_test velox_dwio_dwrf_index_builder_test velox_dwio_dwrf_int_direct_test velox_dwio_dwrf_int_encoder_test velox_dwio_dwrf_layout_planner_test velox_dwio_dwrf_ratio_checker_test velox_dwio_dwrf_reader_base_test velox_dwio_dwrf_reader_test velox_dwio_dwrf_rle_test velox_dwio_dwrf_rlev1_encoder_test velox_dwio_dwrf_stream_labels_test velox_dwio_dwrf_stripe_dictionary_cache_test velox_dwio_dwrf_stripe_reader_base_test velox_dwio_dwrf_stripe_stream_test velox_dwio_dwrf_writer_context_test velox_dwio_dwrf_writer_encoding_manager_test velox_dwio_dwrf_writer_sink_test velox_dwio_dwrf_writer_test velox_dwio_iceberg_reader_benchmark velox_dwio_orc_column_statistics_test velox_dwio_orc_reader_filter_test velox_dwio_orc_reader_test velox_dwio_parquet_page_reader_test velox_dwio_parquet_reader_benchmark velox_dwio_parquet_reader_test velox_dwio_parquet_rlebp_decoder_test velox_dwio_parquet_structure_decoder_test velox_dwio_parquet_table_scan_test velox_dwio_parquet_tpch_test velox_dwrf_column_writer_index_test velox_dwrf_column_writer_stats_test velox_dwrf_column_writer_test velox_dwrf_e2e_filter_test velox_dwrf_e2e_reader_test velox_dwrf_e2e_writer_test velox_dwrf_statistics_builder_utils_test velox_dwrf_writer_extended_test velox_dwrf_writer_flush_test velox_example_operator_extensibility velox_example_scan_orc velox_exchange_benchmark velox_exchange_fuzzer velox_exec_SpatialJoinTest velox_exec_bm_duplicate_project velox_exec_infra_test velox_exec_test_group0 velox_exec_test_group1 velox_exec_test_group2 velox_exec_test_group3 velox_exec_test_group4 velox_exec_test_group5 velox_exec_test_group6 velox_exec_test_group7 velox_exec_util_test_group0 velox_expression_fuzzer_test velox_expression_fuzzer_unit_test velox_expression_runner_test velox_expression_runner_unit_test velox_expression_test velox_expression_verifier_unit_test velox_filemetadata_test velox_filter_project_benchmark velox_function_dynamic_link_test velox_function_registry_test velox_functions_aggregates_test velox_functions_benchmarks_compare velox_functions_benchmarks_row_writer_no_nulls velox_functions_benchmarks_simdjson_function_with_expr velox_functions_benchmarks_string_writer_no_nulls velox_functions_benchmarks_url velox_functions_iceberg_test velox_functions_lib_test velox_functions_prestosql_benchmarks_array_contains velox_functions_prestosql_benchmarks_array_min_max velox_functions_prestosql_benchmarks_array_position velox_functions_prestosql_benchmarks_array_sum velox_functions_prestosql_benchmarks_bitwise velox_functions_prestosql_benchmarks_cardinality velox_functions_prestosql_benchmarks_comparisons velox_functions_prestosql_benchmarks_concat velox_functions_prestosql_benchmarks_date_time velox_functions_prestosql_benchmarks_field_reference velox_functions_prestosql_benchmarks_generic velox_functions_prestosql_benchmarks_in velox_functions_prestosql_benchmarks_map_concat velox_functions_prestosql_benchmarks_map_except velox_functions_prestosql_benchmarks_map_input velox_functions_prestosql_benchmarks_map_intersect velox_functions_prestosql_benchmarks_map_subscript velox_functions_prestosql_benchmarks_map_zip_with velox_functions_prestosql_benchmarks_not velox_functions_prestosql_benchmarks_regexp_replace velox_functions_prestosql_benchmarks_row velox_functions_prestosql_benchmarks_string_ascii_utf_functions velox_functions_prestosql_benchmarks_uuid_cast velox_functions_prestosql_benchmarks_width_bucket velox_functions_prestosql_benchmarks_zip velox_functions_prestosql_benchmarks_zip_with velox_functions_spark_aggregates_test velox_functions_spark_test velox_functions_test velox_fuzzer_connector_test velox_gcs_file_test velox_gcs_insert_test velox_gcs_multiendpoints_test velox_hash_benchmark velox_hash_join_build_benchmark velox_hash_join_list_result_benchmark velox_hash_join_prepare_join_table_benchmark velox_hdfs_file_test velox_hdfs_insert_test velox_hive_connector_test velox_hive_iceberg_deletion_vector_test velox_hive_iceberg_deletion_vector_writer_test velox_hive_iceberg_dwrf_insert_test velox_hive_iceberg_equality_delete_test velox_hive_iceberg_insert_test velox_hive_iceberg_test velox_hive_partition_function_benchmark velox_in_10_min_demo velox_join_fuzzer velox_key_encoder_test velox_mark_distinct_fuzzer velox_mark_sorted_benchmark velox_memory_arbitration_fuzzer velox_memory_test velox_orderby_benchmark velox_parquet_e2e_filter_test velox_parquet_writer_sink_test velox_parquet_writer_test velox_presto_types_fuzzer_utils_test velox_query_replayer velox_re2_functions_benchmarks velox_row_number_fuzzer velox_rpc_operator_test velox_s3file_test velox_s3insert_test velox_s3metrics_test velox_s3multiendpoints_test velox_s3read_test velox_s3registration_test velox_serializer_test_group0 velox_simple_aggregate_test velox_sort_benchmark velox_spark_query_runner_test velox_spark_windows_test velox_sparksql_benchmarks_from_json velox_sparksql_benchmarks_get_funcs velox_sparksql_benchmarks_in velox_spatial_join_benchmark velox_spatial_join_fuzzer velox_spiller_aggregate_benchmark velox_spiller_join_benchmark velox_streaming_aggregation_benchmark velox_table_evolution_fuzzer_test velox_text_reader_test velox_text_writer_test velox_tool_trace_test velox_topn_row_number_fuzzer velox_tpcds_benchmark velox_tpcds_connector_test velox_tpch_benchmark velox_tpch_connector_test velox_tpch_speed_test velox_wave_benchmark velox_wave_exec_test velox_window_fuzzer_test velox_window_prefixsort_benchmark velox_window_sub_partitioned_sort_benchmark velox_windows_agg_test velox_windows_rank_test velox_windows_value_test velox_writer_fuzzer_test

Total affected: 247/575 targets

Affected targets (247)

Directly changed (2)

Target Changed Files
velox_dwio_dwrf_column_reader_test TestColumnReader.cpp
velox_dwio_dwrf_reader SelectiveDecimalColumnReader.cpp, SelectiveDecimalColumnReader.h, SelectiveDwrfReader.cpp

Transitively affected (245)

  • aggregate_companion_functions_test
  • physical_size_aggregator_test
  • presto_sql_test
  • spark_aggregation_fuzzer_test
  • spark_expression_fuzzer_test
  • velox_abfs_test
  • velox_aggregates_GeometryAggregateTest
  • velox_aggregates_reduce_agg_bm
  • velox_aggregates_simple_aggregates_bm
  • velox_aggregates_string_keys_bm
  • velox_aggregates_test_group0
  • velox_aggregates_test_group1
  • velox_aggregates_test_group2
  • velox_aggregates_test_group3
  • velox_aggregates_test_group4
  • velox_aggregation_fuzzer
  • velox_aggregation_fuzzer_base
  • velox_aggregation_fuzzer_test
  • velox_aggregation_result_verifier
  • velox_aggregation_runner_test
  • velox_benchmark_array_writer_no_nulls
  • velox_benchmark_array_writer_with_nulls
  • velox_benchmark_map_writer_no_nulls
  • velox_benchmark_map_writer_with_nulls
  • velox_benchmark_nested_array_writer_no_nulls
  • velox_benchmark_nested_array_writer_with_nulls
  • velox_cache_fuzzer
  • velox_common_test
  • velox_core_test
  • velox_driver_test
  • velox_duckdb_conversion_test
  • velox_dwio_cache_test
  • velox_dwio_dwrf_buffered_output_stream_test
  • velox_dwio_dwrf_byte_rle_encoder_test
  • velox_dwio_dwrf_byte_rle_test
  • velox_dwio_dwrf_checksum_test
  • velox_dwio_dwrf_column_statistics_test
  • velox_dwio_dwrf_compression_test
  • velox_dwio_dwrf_config_test
  • velox_dwio_dwrf_data_buffer_holder_test
  • velox_dwio_dwrf_decompression_test
  • velox_dwio_dwrf_decryption_test
  • velox_dwio_dwrf_dictionary_encoder_test
  • velox_dwio_dwrf_dictionary_encoding_utils_test
  • velox_dwio_dwrf_encoding_selector_test
  • velox_dwio_dwrf_encryption_test
  • velox_dwio_dwrf_flush_policy_test
  • velox_dwio_dwrf_index_builder_test
  • velox_dwio_dwrf_int_direct_test
  • velox_dwio_dwrf_int_encoder_test
  • velox_dwio_dwrf_layout_planner_test
  • velox_dwio_dwrf_ratio_checker_test
  • velox_dwio_dwrf_reader_base_test
  • velox_dwio_dwrf_reader_test
  • velox_dwio_dwrf_rle_test
  • velox_dwio_dwrf_rlev1_encoder_test
  • velox_dwio_dwrf_stream_labels_test
  • velox_dwio_dwrf_stripe_dictionary_cache_test
  • velox_dwio_dwrf_stripe_reader_base_test
  • velox_dwio_dwrf_stripe_stream_test
  • velox_dwio_dwrf_writer_context_test
  • velox_dwio_dwrf_writer_encoding_manager_test
  • velox_dwio_dwrf_writer_sink_test
  • velox_dwio_dwrf_writer_test
  • velox_dwio_iceberg_reader_benchmark
  • velox_dwio_iceberg_reader_benchmark_lib
  • velox_dwio_orc_column_statistics_test
  • velox_dwio_orc_reader
  • velox_dwio_orc_reader_filter_test
  • velox_dwio_orc_reader_test
  • velox_dwio_parquet_page_reader_test
  • velox_dwio_parquet_reader_benchmark
  • velox_dwio_parquet_reader_benchmark_lib
  • velox_dwio_parquet_reader_test
  • velox_dwio_parquet_rlebp_decoder_test
  • velox_dwio_parquet_structure_decoder_test
  • velox_dwio_parquet_table_scan_test
  • velox_dwio_parquet_tpch_test
  • velox_dwrf_column_writer_index_test
  • velox_dwrf_column_writer_stats_test
  • velox_dwrf_column_writer_test
  • velox_dwrf_e2e_filter_test
  • velox_dwrf_e2e_reader_test
  • velox_dwrf_e2e_writer_test
  • velox_dwrf_statistics_builder_utils_test
  • velox_dwrf_test_utils
  • velox_dwrf_writer_extended_test
  • velox_dwrf_writer_flush_test
  • velox_example_operator_extensibility
  • velox_example_scan_orc
  • velox_exchange_benchmark
  • velox_exchange_fuzzer
  • velox_exec_SpatialJoinTest
  • velox_exec_bm_duplicate_project
  • velox_exec_infra_test
  • velox_exec_test_group0
  • velox_exec_test_group1
  • velox_exec_test_group2
  • velox_exec_test_group3
  • velox_exec_test_group4
  • velox_exec_test_group5
  • velox_exec_test_group6
  • velox_exec_test_group7
  • velox_exec_test_lib
  • velox_exec_util_test_group0
  • velox_expression_fuzzer
  • velox_expression_fuzzer_test
  • velox_expression_fuzzer_unit_test
  • velox_expression_runner
  • velox_expression_runner_test
  • velox_expression_runner_unit_test
  • velox_expression_test
  • velox_expression_test_utility
  • velox_expression_verifier
  • velox_expression_verifier_unit_test
  • velox_filemetadata_test
  • velox_filter_project_benchmark
  • velox_function_dynamic_link_test
  • velox_function_registry_test
  • velox_functions_aggregates_test
  • velox_functions_aggregates_test_lib
  • velox_functions_benchmarks_compare
  • velox_functions_benchmarks_row_writer_no_nulls
  • velox_functions_benchmarks_simdjson_function_with_expr
  • velox_functions_benchmarks_string_writer_no_nulls
  • velox_functions_benchmarks_url
  • velox_functions_iceberg_test
  • velox_functions_lib_test
  • velox_functions_prestosql_benchmarks_array_contains
  • velox_functions_prestosql_benchmarks_array_min_max
  • velox_functions_prestosql_benchmarks_array_position
  • velox_functions_prestosql_benchmarks_array_sum
  • velox_functions_prestosql_benchmarks_bitwise
  • velox_functions_prestosql_benchmarks_cardinality
  • velox_functions_prestosql_benchmarks_comparisons
  • velox_functions_prestosql_benchmarks_concat
  • velox_functions_prestosql_benchmarks_date_time
  • velox_functions_prestosql_benchmarks_field_reference
  • velox_functions_prestosql_benchmarks_generic
  • velox_functions_prestosql_benchmarks_in
  • velox_functions_prestosql_benchmarks_map_concat
  • velox_functions_prestosql_benchmarks_map_except
  • velox_functions_prestosql_benchmarks_map_input
  • velox_functions_prestosql_benchmarks_map_intersect
  • velox_functions_prestosql_benchmarks_map_subscript
  • velox_functions_prestosql_benchmarks_map_zip_with
  • velox_functions_prestosql_benchmarks_not
  • velox_functions_prestosql_benchmarks_regexp_replace
  • velox_functions_prestosql_benchmarks_row
  • velox_functions_prestosql_benchmarks_string_ascii_utf_functions
  • velox_functions_prestosql_benchmarks_uuid_cast
  • velox_functions_prestosql_benchmarks_width_bucket
  • velox_functions_prestosql_benchmarks_zip
  • velox_functions_prestosql_benchmarks_zip_with
  • velox_functions_spark_aggregates_test
  • velox_functions_spark_test
  • velox_functions_test
  • velox_functions_test_lib
  • velox_functions_window_test_lib
  • velox_fuzzer_connector_test
  • velox_fuzzer_util
  • velox_gcs_file_test
  • velox_gcs_insert_test
  • velox_gcs_multiendpoints_test
  • velox_hash_benchmark
  • velox_hash_join_build_benchmark
  • velox_hash_join_list_result_benchmark
  • velox_hash_join_prepare_join_table_benchmark
  • velox_hdfs_file_test
  • velox_hdfs_insert_test
  • velox_hive_connector_test
  • velox_hive_iceberg_deletion_vector_test
  • velox_hive_iceberg_deletion_vector_writer_test
  • velox_hive_iceberg_dwrf_insert_test
  • velox_hive_iceberg_equality_delete_test
  • velox_hive_iceberg_insert_test
  • velox_hive_iceberg_test
  • velox_hive_partition_function_benchmark
  • velox_in_10_min_demo
  • velox_join_fuzzer
  • velox_key_encoder_test
  • velox_mark_distinct_fuzzer
  • velox_mark_distinct_fuzzer_lib
  • velox_mark_sorted_benchmark
  • velox_memory_arbitration_fuzzer
  • velox_memory_test
  • velox_orderby_benchmark
  • velox_parquet_e2e_filter_test
  • velox_parquet_writer_sink_test
  • velox_parquet_writer_test
  • velox_presto_types_fuzzer_utils_test
  • velox_query_benchmark
  • velox_query_replayer
  • velox_query_trace_replayer_base
  • velox_re2_functions_benchmarks
  • velox_row_number_fuzzer
  • velox_row_number_fuzzer_lib
  • velox_rpc_operator_test
  • velox_s3file_test
  • velox_s3insert_test
  • velox_s3metrics_test
  • velox_s3multiendpoints_test
  • velox_s3read_test
  • velox_s3registration_test
  • velox_serializer_test_group0
  • velox_simple_aggregate_test
  • velox_sort_benchmark
  • velox_spark_query_runner
  • velox_spark_query_runner_test
  • velox_spark_windows_test
  • velox_sparksql_benchmarks_from_json
  • velox_sparksql_benchmarks_get_funcs
  • velox_sparksql_benchmarks_in
  • velox_spatial_join_benchmark
  • velox_spatial_join_fuzzer
  • velox_spill_fuzzer_base_lib
  • velox_spiller_aggregate_benchmark
  • velox_spiller_aggregate_benchmark_base
  • velox_spiller_join_benchmark
  • velox_spiller_join_benchmark_base
  • velox_streaming_aggregation_benchmark
  • velox_table_evolution_fuzzer_test
  • velox_text_reader_test
  • velox_text_writer_test
  • velox_tool_trace_test
  • velox_topn_row_number_fuzzer
  • velox_topn_row_number_fuzzer_lib
  • velox_tpcds_benchmark
  • velox_tpcds_benchmark_lib
  • velox_tpcds_connector_test
  • velox_tpch_benchmark
  • velox_tpch_benchmark_lib
  • velox_tpch_connector_test
  • velox_tpch_speed_test
  • velox_wave_benchmark
  • velox_wave_exec_test
  • velox_window_fuzzer
  • velox_window_fuzzer_test
  • velox_window_prefixsort_benchmark
  • velox_window_sub_partitioned_sort_benchmark
  • velox_windows_agg_test
  • velox_windows_rank_test
  • velox_windows_value_test
  • velox_writer_fuzzer
  • velox_writer_fuzzer_test

Fast path • Graph from main@fd130f44a388ce8ece4ce629fd4c0ceb45b60942

Copy link
Copy Markdown
Collaborator

@jinchengchenghh jinchengchenghh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your fix, please add the test

// in getIntValues(); in that case the Gluten fallback-tag logic will
// ensure symmetric scan behaviour at the join level.
: SelectiveColumnReader(
(requestedType && requestedType->isDecimal() &&
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not directly send requestedType to SelectiveColumnReader?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if other types is OK.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please align with

  SelectiveIntegerColumnReader(
      const TypePtr& requestedType,
      dwio::common::FormatParams& params,
      velox::common::ScanSpec& scanSpec,
      std::shared_ptr<const dwio::common::TypeWithId> fileType)
      : SelectiveColumnReader(
            requestedType,
            std::move(fileType),
            params,
            scanSpec) {}

The SelectiveColumnReader should decide if it is supported, and throw exception if it is not supported, please also open a PR to verify if this PR can pass all the Gluten unit tests

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conversion support status is

requestedType_ is the output type the reader materializes, while file storage type comes from fileType_.

Copy link
Copy Markdown
Contributor Author

@beliefer beliefer May 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SelectiveColumnReader should decide if it is supported, and throw exception if it is not supported, please also open a PR to verify if this PR can pass all the Gluten unit tests

I created a PR apache/gluten#12061 to verify if this PR can pass all the Gluten unit tests. Do we need wait this PR merged, before 12061 could run tests ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For std::move(fileType), we get the prompt.
std::move of the const variable 'fileType' has no effect; remove std::move() or make the variable non-const
so we should use fileType directly here.

// Use requestedType (table schema) when it is a decimal of the same
// TypeKind as the file type. This allows the reader to rescale values
// from the ORC file's precision/scale to the metastore-declared
// precision/scale, so that NativeScan output matches the vanilla Spark
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restrict the comment to table scan, do not include other unrelated information like join

Copy link
Copy Markdown
Contributor Author

@beliefer beliefer May 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about
so that NativeScan output matches the vanilla Spark scan path and decimal join-key comparisons succeed.
->
so that NativeScan output matches the vanilla Spark scan. ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// When the read schema (requestedType) differs from the file schema,
// prefer using requestedType for decoding as long as the conversion is
// supported (e.g. reading decimal with different scale). This allows the reader to
// interpret values according to the table schema, so that NativeScan
// matches the vanilla Spark scan behavior.
//

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@jinchengchenghh
Copy link
Copy Markdown
Collaborator

And add a brief description about this issue in PR description

@beliefer beliefer requested a review from jinchengchenghh May 9, 2026 07:08
@beliefer beliefer force-pushed the 17462 branch 2 times, most recently from bb9f2bc to 86f213b Compare May 11, 2026 05:59
// NativeScan matches the vanilla Spark scan behavior.
//
// When the TypeKinds differ (e.g. file is HUGEINT but table declares
// BIGINT) we fall back to the file type to avoid buffer-size mismatches
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the comment on getIntValues, it does not fallback to file type, please remove them

  /// Returns integer values for 'rows' cast to the width of 'requestedType' in
  /// '*result'.
  void getIntValues(
      const RowSet& rows,
      const TypePtr& requestedType,
      VectorPtr* result);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

Copy link
Copy Markdown
Contributor

@mbasmanova mbasmanova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the fix.

The PR description is still vague — it says "pass the request type into SelectiveColumnReader" but doesn't explain the problem. Please add the explanation of the Hive DECIMAL(38,18) behavior to the PR description.

The code comment says "prefer using requestedType ... as long as the conversion is supported" — but the code unconditionally passes requestedType with no compatibility check or fallback. The comment implies conditional logic that doesn't exist. What happens if requestedType is incompatible (e.g. non-decimal type)? Please add a test for unsupported conversions, and either add the compatibility check or simplify the comment.

The 4 test cases repeat ~30 lines of identical setup (encoding, stream mocks, reader construction). Extract a helper that takes the varying parts (data buffer, scale buffer, file type, requested type, expected values) to eliminate the copy-paste.

Use assertEqualVectors against an expected vector instead of individual EXPECT_EQ calls with C-style (long long) casts.

Use ROW("col_0", DECIMAL(38, 18)) instead of HiveTypeParser().parse("struct<col_0:decimal(38, 18)>").

The background comment in the test (Hive ORC always writes DECIMAL(38,18) in the footer, per-row scale in the SECONDARY stream, reader used footer scale instead of metastore scale) belongs in the API — on the SelectiveDecimalColumnReader constructor or requestedType parameter — not in the test file.

@beliefer
Copy link
Copy Markdown
Contributor Author

@jinchengchenghh Could you explain why you suggested me make the change from

requestedType && requestedType->isDecimal() &&
           requestedType->kind() == fileType->type()->kind())
              ? requestedType
              : fileType->type()

to
requestedType ?
As @mbasmanova said, the code comment says "prefer using requestedType ... as long as the conversion is supported" — but the code unconditionally passes requestedType with no compatibility check or fallback.

@beliefer
Copy link
Copy Markdown
Contributor Author

@mbasmanova Thank you for the comments.

The PR description is still vague — it says "pass the request type into SelectiveColumnReader" but doesn't explain the problem. Please add the explanation of the Hive DECIMAL(38,18) behavior to the PR description.

I added the explanation of the Hive DECIMAL(38,18) behavior to the PR description.

@beliefer beliefer force-pushed the 17462 branch 2 times, most recently from 87ec8ef to 62ed47f Compare May 14, 2026 10:24
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 14, 2026

CI Failure Analysis

Auto-generated by the CI Failure Analysis workflow. This comment is updated in place each time CI fails on a new commit, so it always reflects the latest run — re-pushing or re-running CI will refresh the analysis below. Last updated 2026-05-15 08:14:30 UTC from workflow run 25905832026.

🔴 Expression Fuzzer with Presto SOT — FUZZER Failure View logs

All 4 instances failed (seeds: 1034627224, 858084286, 1012776691, 437388568)

ExpressionVerifier.cpp:475 — Velox and reference DB results don't match

Each instance: "Expected 100, got 100" — row count matches, but 2 rows differ.
The mismatched values are TIMESTAMP WITH TIME ZONE values that differ by
exactly 1 hour (14,745,600,000 in the (millis << 12 | tz_id) encoding).

Plans involve: parse_datetime(..., 'yyyy-MM-dd HH:mm:ss.SSS ZZZ') inside
coalesce/try, materialized through row_constructor/transform.

🔴 Join Fuzzer — FUZZER Failure View logs

3 of 4 instances failed (seeds: 394900408, 135349143, 522623826)

JoinFuzzer.cpp:740 — Velox and Reference results don't match

Instance 1 (seed=394900408): Expected 1000, got 1000 — 1 extra row, 1 missing row.
  Extra:   ...2927052057047648100...
  Missing: ...2927052071793248100...
  Diff = 14,745,600,000 = 3,600,000 ms << 12 → exactly 1 hour in TIMESTAMP WITH TIME ZONE encoding.

🔴 Aggregation Fuzzer with Presto as source of truth — FUZZER Failure View logs

3 of 4 instances failed (seeds: 580222099, 408420116, 817894527)

AggregationFuzzer.cpp:1066 — Velox and reference DB results don't match

Instance 2 (seed=580222099): plan uses ARRAY<TIMESTAMP WITH TIME ZONE> via
  parse_datetime with 'yyyy-MM-dd HH:mm:ss.SSS ZZZ'/'ZZ' patterns.
  1 extra row, 1 missing row — value diff = 14,745,600,000 (1-hour offset).

Instance 3 (seed=408420116): plan uses bitwise_xor_agg with TIMESTAMP WITH TIME ZONE grouping keys.
Instance 4 (seed=817894527): plan uses stddev with TIMESTAMP WITH TIME ZONE grouping keys.

🔴 Window Fuzzer with Presto as source of truth — FUZZER Failure View logs

1 of 4 instances failed (seed: 568763331)

WindowFuzzer.cpp:802 — Velox and reference DB results don't match

Instance 2 (seed=568763331): plan uses variance(c0) with partition keys including
  TIMESTAMP WITH TIME ZONE (built via parse_datetime coalesce pattern).
  43 extra rows, 43 missing rows — same 1-hour offset pattern.

Correlation with PR changes:

This PR (#17463) modifies only DWRF decimal column reader files:

  • velox/dwio/dwrf/reader/SelectiveDecimalColumnReader.cpp
  • velox/dwio/dwrf/reader/SelectiveDecimalColumnReader.h
  • velox/dwio/dwrf/reader/SelectiveDwrfReader.cpp
  • velox/dwio/dwrf/test/TestColumnReader.cpp

The changes pass requestedType (instead of fileType) to SelectiveDecimalColumnReader so decimal values are materialized at the table-schema scale. These changes do not touch any TIMESTAMP, timezone, expression evaluation, or fuzzer code. The failures are unrelated to this PR.

Known issues:

  • #17522 — Fuzzer mismatch on TIMESTAMP WITH TIME ZONE: Velox value off by 1 hour vs Presto — This open issue describes exactly the same failure pattern across all four fuzzers. The mismatched values are TIMESTAMP WITH TIME ZONE values that differ from Presto by exactly 1 hour (14,745,600,000 in the packed encoding), with timezone-id bits unchanged.
  • The last 5 consecutive Fuzzer Jobs runs on main have all failed with the same pattern. This is a pre-existing failure on main, not introduced by this PR.

Reproduce locally:

# Expression Fuzzer (any of the 4 seeds will reproduce)
./_build/release/velox/expression/fuzzer/velox_expression_fuzzer_test \
    --seed 1034627224 \
    --enable_variadic_signatures \
    --velox_fuzzer_enable_complex_types \
    --lazy_vector_generation_ratio 0.2 \
    --common_dictionary_wraps_generation_ratio=0.3 \
    --velox_fuzzer_enable_column_reuse \
    --velox_fuzzer_enable_expression_reuse \
    --enable_dereference \
    --duration_sec 300 \
    --special_forms="cast,coalesce,if" \
    --velox_fuzzer_max_level_of_nesting=1 \
    --presto_url=http://127.0.0.1:8080

# Join Fuzzer
./_build/release/velox/exec/fuzzer/velox_join_fuzzer --seed 394900408 --duration_sec 300

# Aggregation Fuzzer
./_build/release/velox/functions/prestosql/fuzzer/velox_aggregation_fuzzer_test --seed 580222099 --duration_sec 300

# Window Fuzzer
./_build/release/velox/functions/prestosql/fuzzer/velox_window_fuzzer_test --seed 568763331 --duration_sec 300

Recommended fix:

No action needed on this PR. The fuzzer failures are tracked in #17522 and are pre-existing on main. The root cause is a 1-hour offset bug in the TIMESTAMP WITH TIME ZONE / parse_datetime codepath affecting Velox-vs-Presto comparison.

Copy link
Copy Markdown
Contributor

@mbasmanova mbasmanova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@beliefer, Thank you for iterating on the feedback!

Test comments are verbose and duplicate the constructor doc. The 5-line block comment before the tests references the constructor comment — redundant. Replace with a one-liner: "Verify that when the file type doesn't match the metastore type, the metastore type wins and data is rescaled accordingly." Per-test comments restate what the test names and parameters already show (e.g., testDecimal128RequestedTypeScaleZero with DECIMAL(38, 18)DECIMAL(20, 0) is self-explanatory). The // DATA: values 1, 2, 3, 4 as zigzag-encoded varints comment is repeated across tests — the parameter name is sufficient. The 4-line comment on testDecimalRequestedTypeBigintRejected explaining which code path raises the error is implementation detail. Please trim all test comments to only what is non-obvious from the code.

Rejection tests duplicate mock setup. testDecimalRequestedTypeBigintRejected and testDecimalRequestedTypeDoubleRejected have identical mock setup. Please extract a helper or combine into one test that checks both types.

Test names. Drop the test prefix and use shortDecimal / longDecimal instead of Decimal64 / Decimal128 (e.g., testDecimal128RequestedTypeScaleZerolongDecimalRequestedTypeScaleZero).

Simplify call sites.

  • folly::Range(dataBuffer, std::size(dataBuffer)) — just pass dataBuffer, folly::Range constructs directly from a C array.
  • {int128_t{1}, int128_t{2}, int128_t{3}, int128_t{4}} — simplify to {1, 2, 3, 4}, the template parameter already specifies the type.
  • ROW({"col_0"}, {DECIMAL(12, 5)}) — the helper can wrap the type in ROW("col_0", type) internally. Callers should just pass DECIMAL(12, 5) and DECIMAL(10, 2).
  • ROW({"col_0"}, {DECIMAL(38, 18)}) — drop the braces: ROW("col_0", DECIMAL(38, 18)). Same for ROW({"col_0"}, {BIGINT()}) etc.

Verify full error message in rejection tests. VELOX_ASSERT_THROW(..., "Schema mismatch") only checks a substring. The actual error includes "From Kind: X, To Kind: Y" — please verify the full message including the specific types to ensure the error is precise.

Copy link
Copy Markdown
Contributor

@mbasmanova mbasmanova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the updates! Almost there.

Lint warning. /*read=*/ should be /*readSize=*/ to match the parameter name.

Rejection test loop. Unroll the loop for readability — it's only 2 cases:

VELOX_ASSERT_THROW(
    buildReader(ROW("col_0", BIGINT()), fileType, {}, scanSpec.get()),
    "Schema mismatch, From Kind: HUGEINT, To Kind: BIGINT");
VELOX_ASSERT_THROW(
    buildReader(ROW("col_0", DOUBLE()), fileType, {}, scanSpec.get()),
    "Schema mismatch, From Kind: HUGEINT, To Kind: DOUBLE");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pass request type to SelectiveDecimalColumnReader Join operator lost data due to decimal join key.

3 participants